package com.ygqh.baby.service.impl;

import com.ygqh.baby.ao.*;
import com.ygqh.baby.constant.Constant;
import com.ygqh.baby.mapper.YgSupplierReconciliationMapper;
import com.ygqh.baby.model.OrderInfoForRecon;
import com.ygqh.baby.model.SkuInfoBySupplierRecon;
import com.ygqh.baby.model.YgSkuInfo;
import com.ygqh.baby.po.*;
import com.ygqh.baby.service.*;
import com.ygqh.baby.template.AbstractDiffDateTemplate;
import com.ygqh.baby.utils.DateConvertUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class YgSupplierReconciliationServiceImpl implements YgSupplierReconciliationService {

	@Autowired
	private YgSupplierReconciliationMapper ygSupplierReconciliationMapper;
	@Autowired
	private ScheduleJobService scheduleJobService;
	@Autowired
	private YgSupplierService ygSupplierService;
	@Autowired
	private YgSkuService ygSkuService;
	@Autowired
	private YgFrameCodeService ygFrameCodeService;
	@Autowired
	private YgReturnOrderService ygReturnOrderService;

	@Override
	public List<YgSupplierReconciliation> find() {
		YgSupplierReconciliationExample example = new YgSupplierReconciliationExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return ygSupplierReconciliationMapper.selectByExample(example);
	}

	@Override
	public int findCount() {
		YgSupplierReconciliationExample example = new YgSupplierReconciliationExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return ygSupplierReconciliationMapper.countByExample(example);
	}

	@Override
	public YgSupplierReconciliation findById(Long id) {
		return ygSupplierReconciliationMapper.selectByPrimaryKey(id);
	}

	@Override
	public int save(YgSupplierReconciliation ygSupplierReconciliation) {
		return ygSupplierReconciliationMapper.insertSelective(ygSupplierReconciliation);
	}

	@Override
	public int update(YgSupplierReconciliation ygSupplierReconciliation) {
		return ygSupplierReconciliationMapper.updateByPrimaryKeySelective(ygSupplierReconciliation);
	}

	@Override
	public ResultSet<YgSupplierReconciliation> search(QueryInfo queryInfo, String q, Long supplierId, ContractStatus reconciliationStatus) {
		String reconciliationStatusName = reconciliationStatus == null ? null : reconciliationStatus.name();
		List<YgSupplierReconciliation> list = ygSupplierReconciliationMapper.selectSuper(queryInfo, q, supplierId, reconciliationStatusName, false);
		int count = ygSupplierReconciliationMapper.countSuper(q, supplierId, reconciliationStatusName, false);
		return new ResultSet<>(count, list);
	}

	@Override
	public int deleteSoft(Long[] ids) {
		Assert.notEmpty(ids);
		YgSupplierReconciliationExample example = new YgSupplierReconciliationExample();
		example.createCriteria().andIdIn(Arrays.asList(ids));
		YgSupplierReconciliation record = new YgSupplierReconciliation();
		record.setStatus(DataStatus.Delete);
		return ygSupplierReconciliationMapper.updateByExampleSelective(record, example);
	}

	@Override
	public int deleteSoft(Long id) {
		return this.deleteSoft(new Long[] { id });
	}

	@Override
	public int saveOrUpdate(YgSupplierReconciliation ygSupplierReconciliation) {
		int r;
		if (ygSupplierReconciliation.getId() != null) {
			r = this.update(ygSupplierReconciliation);
		} else {
			r = this.save(ygSupplierReconciliation);
		}
		return r;
	}

	@Override
	public void addSupplierReconciliation(Long supplierId) {
		YgSupplier supplier = ygSupplierService.findById(supplierId);
		YgQuartzJob jobMode = YgQuartzJob.Supplier;
		String jobName = jobMode.getJobName(supplierId.toString());
		ScheduleJob job = scheduleJobService.findJobByJobNames(jobName).get(0);
		Date cronDate = job.getCronDate();
		if (cronDate.after(new Date())) {
			// 计划任务的执行时间在当前时间以后，计划任务不作修改
			return;
		}
		cronDate = addSupplierReconciliation(supplier, DateConvertUtils.getDateStart(cronDate));
		if (supplier.getPaymentCycle() < Constant.STANDARD_DAYS_OF_MONTH) {
			// 按天
			cronDate = DateConvertUtils.addDay(cronDate, supplier.getPaymentCycle());
		} else {
			cronDate = DateConvertUtils.addMonth(cronDate, 1);
		}
		job.setCron(DateConvertUtils.format(cronDate, DateConvertUtils.DATE_FORMAT_CRON));
		job.setCronDate(cronDate);
		Message message = scheduleJobService.updateJobToSchedule(job);
		if (Message.isSuccess(message)) {
			job.setUpdateBy("task");
			job.setUpdateTime(new Date());
			scheduleJobService.update(job);
		}
	}

	private Date addSupplierReconciliation(YgSupplier supplier, Date runTime) {
		List<YgSupplierReconciliation> supplierReconciliationList = this.findBySupplierId(supplier.getId());
		Date startDate;
		if (CollectionUtils.isEmpty(supplierReconciliationList)) {
			// 无统计历史
			startDate = DateConvertUtils.getDateStart(supplier.getCreateTime());
		} else {
			startDate = DateConvertUtils.addDay(supplierReconciliationList.get(0).getEndDate(), 1);
		}
		return new AbstractDiffDateTemplate<YgSupplier>(supplier, supplier.getPaymentCycle(), startDate, runTime) {
			@Override
			public void execute(Date startDate, Date endDate) {
				saveReconciliation(startDate, endDate, supplier);
			}
		}.process();
	}

	@Override
	public void addReconciliantionPastTime(YgSupplier ygSupplier) {
		Date today = DateConvertUtils.getDateStart(new Date());
		if (ygSupplier.getCreateTime().after(today)) {
			// 新建商家
			return;
		}
		this.addSupplierReconciliation(ygSupplier, today);
	}

	@Override
	public void updateByReset(Long id) {
		YgSupplierReconciliation reconciliation = this.findById(id);
		YgSupplier supplier = ygSupplierService.findById(reconciliation.getSupplierId());
		Assert.notNull(supplier, "指定商家不存在");
		this.saveReconciliation(reconciliation.getStartDate(),
				DateConvertUtils.addDay(reconciliation.getEndDate(), 1), supplier);
		this.deleteSoft(id);
	}

	@Override
	public List<SkuInfoBySupplierRecon> findBiSkuInfoList(Date startTime, Date endTime, Long supplierId) {
		return ygSupplierReconciliationMapper.selectBiSkuInfoList(startTime, endTime, supplierId);
	}

	@Override
	public Map<String, Object> findExportData(Long reconciliationId) {
		YgSupplierReconciliation reconciliation = this.findById(reconciliationId);
		Date startTime = reconciliation.getStartDate();
		Date endTime = DateConvertUtils.addDay(reconciliation.getEndDate(), 1);
		YgSupplier supplier = ygSupplierService.findById(reconciliation.getSupplierId());

		List<SkuInfoBySupplierRecon> skuInfoList = this.getSkuInfoForReconciliation(startTime, endTime, supplier);
		processSkuInfo(reconciliation, skuInfoList);

		Map<String, Object> dataMap = new HashMap<>();
		dataMap.put("resultSet", skuInfoList);
		dataMap.put("totalSalePrice", reconciliation.getSalePrice());
		dataMap.put("totalSaleAmount", reconciliation.getSaleAmount());

		BigDecimal totalReturnDifferencePrice = skuInfoList.stream()
				.map(SkuInfoBySupplierRecon::getReturnDifferencePrice)
				.reduce(BigDecimal::add).get();

		dataMap.put("totalReturnDifferencePrice", totalReturnDifferencePrice);
		dataMap.put("totalReturnPrice", reconciliation.getReturnPrice().subtract(totalReturnDifferencePrice));
		dataMap.put("totalReturnAmount", reconciliation.getReturnAmount());
		dataMap.put("totalReconciliationPrice", reconciliation.getReconciliationPrice());
		dataMap.put("supplierName", supplier.getSupplierName());
		if (PaymentMode.Commission.equals(supplier.getPaymentMode())) {
			BigDecimal rate = supplier.getCommissionRate().multiply(BigDecimal.valueOf(100));
			dataMap.put("paymentMode", "佣金比例" + rate
					+ "%，按销售价的" + (BigDecimal.valueOf(100).subtract(rate)) + "%结算");
			dataMap.put("priceMode", "销售价");
		} else {
			dataMap.put("paymentMode", "按成本结算");
			dataMap.put("priceMode", "含税供货价");
		}
		dataMap.put("formula", "结算金额-退货金额");
		dataMap.put("dateInterval", DateConvertUtils.format(reconciliation.getStartDate()) + " ~ "
				+ DateConvertUtils.format(reconciliation.getEndDate()));
		return dataMap;
	}

	@Override
	public Map<String, Object> findExportDataDetail(Date startTime, Date endTime, Long supplierId) {
		YgSupplier supplier = ygSupplierService.findById(supplierId);

		List<OrderInfoForRecon> orderInfoForSold = this.findBiOrderInfoForSold(startTime, endTime, supplier.getId());
		setPriceToOrderInfo(orderInfoForSold, supplier);
		List<OrderInfoForRecon> orderInfoForReturn = this.findBiOrderInfoForReturn(startTime, endTime, supplier.getId());
		setPriceToOrderInfo(orderInfoForReturn, supplier);

		List<OrderInfoForRecon> orderInfoForReturnDifference =
				this.findBiOrderInfoForReturnDifference(startTime, endTime, supplier.getId());

		Map<String, Object> dataMap = new HashMap<>();
		dataMap.put("resultSet", orderInfoForSold);
		dataMap.put("resultSet2", orderInfoForReturn);
		dataMap.put("resultSet3", orderInfoForReturnDifference);
		if (PaymentMode.Commission.equals(supplier.getPaymentMode())) {
			dataMap.put("priceMode", "销售价");
		} else {
			dataMap.put("priceMode", "含税供货价");
		}
		return dataMap;
	}

	/**
	 * 设置价格
	 * @param orderInfoList
	 * @param supplier
	 */
	private void setPriceToOrderInfo(List<OrderInfoForRecon> orderInfoList, YgSupplier supplier) {
		if (CollectionUtils.isEmpty(orderInfoList)) {
			return;
		}
		List<Long> skuIdList = orderInfoList.stream().map(OrderInfoForRecon::getSkuId).collect(Collectors.toList());
		List<YgSkuInfo> skuList = ygSkuService.findSkuInfoListByIds(skuIdList);
		Assert.notEmpty(skuList, "SKU信息异常");
		Map<Long, List<YgSkuInfo>> collect = skuList.stream().collect(Collectors.groupingBy(YgSkuInfo::getSkuId));
		for (OrderInfoForRecon orderInfo : orderInfoList) {
			Assert.isTrue(collect.containsKey(orderInfo.getSkuId()), "SKU信息异常，skuId=" + orderInfo.getSkuId());
			YgSkuInfo skuInfo = collect.get(orderInfo.getSkuId()).get(0);
			BigDecimal price;
			if (PaymentMode.Cost.equals(supplier.getPaymentMode())) {
				price = skuInfo.getCostPrice();
			} else {
				price = skuInfo.getSalesPrice();
				if (skuInfo.getPromotionPrice() != null && skuInfo.getPromotionPrice().compareTo(BigDecimal.ZERO) > 0) {
					price = skuInfo.getPromotionPrice();
				}
			}
			orderInfo.setPrice(price);
		}
	}

	private List<YgSupplierReconciliation> findBySupplierId(Long supplierId) {
		return ygSupplierReconciliationMapper.selectSuper(null, null, supplierId, null, true);
	}

	/**
	 * 商家对账
	 * @param startTime
	 * @param endTime
	 * @param supplier
	 */
	private void saveReconciliation(Date startTime, Date endTime, YgSupplier supplier) {
		YgSupplierReconciliation sr = new YgSupplierReconciliation();

		List<SkuInfoBySupplierRecon> skuInfoList = getSkuInfoForReconciliation(startTime, endTime, supplier);
		processSkuInfo(sr, skuInfoList);

		String reconciliationCode = "SR" + ygFrameCodeService.getFrameCode(CodeType.Settlement, new Date(), 2);
		sr.setReconciliationCode(reconciliationCode);
		sr.setSupplierId(supplier.getId());
		sr.setStartDate(startTime);
		sr.setEndDate(DateConvertUtils.addDay(endTime, -1));

		this.save(sr);
	}

	/**
	 * 处理对账商品信息
	 * @param sr
	 * @param skuInfo
	 */
	private void processSkuInfo(YgSupplierReconciliation sr, List<SkuInfoBySupplierRecon> skuInfo) {
		Long saleAmount = 0L;
		BigDecimal salePrice = BigDecimal.ZERO;
		Long returnAmount = 0L;
		BigDecimal returnPrice = BigDecimal.ZERO;
		if (CollectionUtils.isNotEmpty(skuInfo)) {
			for (SkuInfoBySupplierRecon info : skuInfo) {
				saleAmount += info.getSaleAmount();
				returnAmount += info.getReturnAmount();
				salePrice = salePrice.add(info.getSalePrice());
				returnPrice = returnPrice.add(info.getReturnPrice()).add(info.getReturnDifferencePrice());
			}
		}
		sr.setSaleAmount(saleAmount);
		sr.setSalePrice(salePrice);
		sr.setReturnAmount(returnAmount);
		sr.setReturnPrice(returnPrice);
		sr.setReconciliationPrice(salePrice.subtract(returnPrice));
	}

	/**
	 * 获取需对账的商品信息
	 *
	 * 成本对账：以SKU当前设置的成本价处理
	 * 佣金对账：以SKU当前设置的销售价（拼团商品以拼团价）处理
	 * @param startTime
	 * @param endTime
	 * @param supplier
	 * @return
	 */
	private List<SkuInfoBySupplierRecon> getSkuInfoForReconciliation(Date startTime, Date endTime, YgSupplier supplier) {
		List<SkuInfoBySupplierRecon> skuInfoList = new ArrayList<>();
		skuInfoList.addAll(getSkuInfoForReconciliationByOrdinary(startTime, endTime, supplier));
		skuInfoList.addAll(getSkuInfoForReconciliationByNotReturnProduct(startTime, endTime, supplier));
		return skuInfoList;
	}

	/**
	 * 处理退差价单
	 *
	 * @param startTime
	 * @param endTime
	 * @param supplier
	 * @return
	 */
	private List<SkuInfoBySupplierRecon> getSkuInfoForReconciliationByNotReturnProduct(Date startTime, Date endTime,
																					   YgSupplier supplier) {
		List<SkuInfoBySupplierRecon> skuInfoList = new ArrayList<>();
		// 获取已完成退差价单
		List<YgReturnOrder> returnOrderList = ygReturnOrderService.findByReturnStatusHasDetail(startTime, endTime,
				null, ReturnType.Return, supplier.getId(), null, ReturnReasonType.ReturnDifference,
				ReturnStatus.Complete);
		if (CollectionUtils.isEmpty(returnOrderList)) {
			return skuInfoList;
		}
		Map<Long, SkuInfoBySupplierRecon> map = new HashMap<>();
		for (YgReturnOrder returnOrder : returnOrderList) {
			BigDecimal lastRefundPrice = returnOrder.getReturnPrice();
			int size = returnOrder.getReturnOrderDetails().size();
			for (int i = 0; i < size; i++) {
				YgReturnOrderDetail detail = returnOrder.getReturnOrderDetails().get(i);
				SkuInfoBySupplierRecon info = map.get(detail.getSourceSkuId());
				if (info == null) {
					info = new SkuInfoBySupplierRecon();
					info.setSkuId(detail.getSourceSkuId());
					info.setReturnDifferencePrice(BigDecimal.ZERO);
				}
				BigDecimal price;
				if (i == size - 1) {
					price = lastRefundPrice;
				} else {
					price = returnOrder.getRefundPrice()
							.divide(BigDecimal.valueOf(size), 2, BigDecimal.ROUND_HALF_UP);
					lastRefundPrice = lastRefundPrice.subtract(price);
				}
				info.setReturnDifferencePrice(info.getReturnDifferencePrice().add(price));
				map.put(detail.getSourceSkuId(), info);
			}
		}
		skuInfoList.addAll(map.values());
		return skuInfoList;
	}

	/**
	 * 处理正常单据
	 *
	 * @param startTime
	 * @param endTime
	 * @param supplier
	 * @return
	 */
	private List<SkuInfoBySupplierRecon> getSkuInfoForReconciliationByOrdinary(Date startTime, Date endTime,
																			   YgSupplier supplier) {
		List<SkuInfoBySupplierRecon> skuInfoList =
				this.findBiSkuInfoList(startTime, endTime, supplier.getId());
		if (CollectionUtils.isEmpty(skuInfoList)) {
			return new ArrayList<>();
		}
		List<Long> skuIdList = skuInfoList.stream().map(SkuInfoBySupplierRecon::getSkuId).collect(Collectors.toList());
		List<YgSkuInfo> skuList = ygSkuService.findSkuInfoListByIds(skuIdList);
		Assert.notEmpty(skuList, "SKU信息异常");
		Map<Long, List<YgSkuInfo>> collect = skuList.stream().collect(Collectors.groupingBy(YgSkuInfo::getSkuId));
		for (SkuInfoBySupplierRecon skuInfo : skuInfoList) {
			Assert.isTrue(collect.containsKey(skuInfo.getSkuId()), "SKU信息异常，skuId=" + skuInfo.getSkuId());
			YgSkuInfo sku = collect.get(skuInfo.getSkuId()).get(0);
			if (PaymentMode.Cost.equals(supplier.getPaymentMode())) {
				BigDecimal price = sku.getCostPrice();
				skuInfo.setPrice(price);
				skuInfo.setSalePrice(price.multiply(BigDecimal.valueOf(skuInfo.getSaleAmount())));
				skuInfo.setReturnPrice(price.multiply(BigDecimal.valueOf(skuInfo.getReturnAmount())));
			} else {
				BigDecimal price = sku.getSalesPrice();
				if (sku.getPromotionPrice() != null && sku.getPromotionPrice().compareTo(BigDecimal.ZERO) > 0) {
					price = sku.getPromotionPrice();
				}
				skuInfo.setPrice(price);
				BigDecimal rate = BigDecimal.valueOf(1).subtract(supplier.getCommissionRate());
				BigDecimal paymentPrice = price.multiply(rate).setScale(2, BigDecimal.ROUND_HALF_DOWN);
				skuInfo.setSalePrice(paymentPrice.multiply(BigDecimal.valueOf(skuInfo.getSaleAmount())));
				skuInfo.setReturnPrice(paymentPrice.multiply(BigDecimal.valueOf(skuInfo.getReturnAmount())));
			}
			skuInfo.setReconciliationPrice(skuInfo.getSalePrice().subtract(skuInfo.getReturnPrice()));
		}
		return skuInfoList;
	}

	/**
	 * 查询商家对账订单明细信息
	 * @param startTime
	 * @param endTime
	 * @param supplierId
	 * @return
	 */
	private List<OrderInfoForRecon> findBiOrderInfoForSold(Date startTime, Date endTime, Long supplierId) {
		return ygSupplierReconciliationMapper.selectBiOrderInfoForSold(startTime, endTime, supplierId);
	}

	/**
	 * 查询商家对账退款明细信息
	 * @param startTime
	 * @param endTime
	 * @param supplierId
	 * @return
	 */
	private List<OrderInfoForRecon> findBiOrderInfoForReturn(Date startTime, Date endTime, Long supplierId) {
		return ygSupplierReconciliationMapper.selectBiOrderInfoForReturn(startTime, endTime, supplierId);
	}

	/**
	 * 查询商家对账退差价明细信息
	 * @param startTime
	 * @param endTime
	 * @param supplierId
	 * @return
	 */
	private List<OrderInfoForRecon> findBiOrderInfoForReturnDifference(Date startTime, Date endTime, Long supplierId) {
		List<OrderInfoForRecon> orderInfoList = new ArrayList<>();
		// 获取已完成退差价单
		List<YgReturnOrder> returnOrderList = ygReturnOrderService.findByReturnStatusHasDetail(startTime, endTime,
				null, ReturnType.Return, supplierId, null, ReturnReasonType.ReturnDifference,
				ReturnStatus.Complete);
		if (CollectionUtils.isEmpty(returnOrderList)) {
			return orderInfoList;
		}
		for (YgReturnOrder returnOrder : returnOrderList) {
			BigDecimal lastRefundPrice = returnOrder.getRefundPrice();
			int size = returnOrder.getReturnOrderDetails().size();
			for (int i = 0; i < size; i++) {
				YgReturnOrderDetail detail = returnOrder.getReturnOrderDetails().get(i);
				OrderInfoForRecon info = new OrderInfoForRecon();
				info.setReturnCode(returnOrder.getReturnCode());
				info.setOrderId(returnOrder.getOrderId().toString());
				info.setProductName(detail.getProductName());
				info.setShortName(detail.getShortName());
				info.setSizeName(detail.getSizeName());
				BigDecimal price;
				if (i == size - 1) {
					price = lastRefundPrice;
				} else {
					price = returnOrder.getRefundPrice()
							.divide(BigDecimal.valueOf(size), 2, BigDecimal.ROUND_HALF_UP);
					lastRefundPrice = lastRefundPrice.subtract(price);
				}
				info.setPrice(price);
				orderInfoList.add(info);
			}
		}
		return orderInfoList;
	}
}
